Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: make target manager accessible on driver #14122

Merged
merged 7 commits into from
Jun 22, 2022
Merged

Conversation

brendankenny
Copy link
Member

Should help significantly with #14078. Smoke tests should all pass, but waiting on feedback before touching the unit test mocks :)

This PR elevates TargetManager to a top-level property on Driver. The intention is that TargetManager

  • will be the sole place tracking and attaching to targets/sessions (including wrapping CDPSessions in FR sessions), which should make the execution flow easier to understand and make future changes simpler.
  • will live for as long as Driver does, which includes across passes. It's basically a live view of all the sessions Lighthouse knows about
  • the place to subscribe to all protocol events (with the flattened sessionId included)

The legacy driver basically does these things already, so it was easy to expose a shim on it and keep NetworkMonitor (and its users) on a unified implementation. It's not pretty architecturally, but it is simple (yay) and should only be around until LH 11.

Since TargetManager tracks all sessions and their targetInfo, in the future it could be used for things like, "give me all the iframe sessions" so you can send commands or evaluate() in them easily, but nothing needs that right now and it's harder to include legacy support, so we can wait.

re: @paulirish's #14120 (comment), AFAICT all sessions now have IDs, presumably because pptr is keeping the sessionId-less session to itself. I'd like to verify that and move us to a place where sessionId is required in the all-protocol-events type:

// If sessionId is not set, it means the event was from the root target.
sessionId?: string;

so code will hopefully be forced to contend with it. Meanwhile in this PR, session drops the sessionId so it's like CDPSession. If you're subscribing to a single session's events, there's no need for a session ID. We can follow up and make the session event handling simpler, but I didn't want the changes in this PR interleaved with that change.

@brendankenny brendankenny requested a review from a team as a code owner June 13, 2022 20:15
@brendankenny brendankenny requested review from connorjclark and removed request for a team June 13, 2022 20:15
Comment on lines +75 to +78
const cdpSession = await this._page.target().createCDPSession();
this._targetManager = new TargetManager(cdpSession);
await this._targetManager.enable();
this.defaultSession = this._targetManager.rootSession();
Copy link
Member Author

@brendankenny brendankenny Jun 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because TargetManager is in charge of creating FR ProtocolSessions from CDPSessions, and we want to eventually make those sessions available for gatherers to access directly, Driver now gets its driver.defaultSession from targetManager instead of making it itself. This is a little weird, but otherwise we have two different session objects pointing to the same thing. This seemed conceptually simpler (driver setup is a little more involved but it means the set of all active sessions includes defaultSession) but open to ideas.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big fan of avoiding the double session object! (I was seeing that at the CDP traffic level. so weird.)

* 'Domain.method2Name': {method: 'Domain.method2Name', params: EventPayload2},
* }
*/
type RawEventMessageRecord = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an unchanged move from below, but it was previously scoped to the file and we need it exported now

this._networkMonitor.on('protocolmessage', this._onProtocolMessage);
this._networkMonitor.enable();
driver.targetManager.on('protocolevent', this._onProtocolMessage);
await driver.defaultSession.sendCommand('Page.enable');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have so many Page.enables in LH that this has to be unnecessary, but this matches the behavior of the this._networkMonitor.enable() call

Copy link
Collaborator

@connorjclark connorjclark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(first pass)

lighthouse-core/gather/driver/target-manager.js Outdated Show resolved Hide resolved
lighthouse-core/gather/driver.js Outdated Show resolved Hide resolved
lighthouse-core/gather/driver/target-manager.js Outdated Show resolved Hide resolved
Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lots of great improvements here. thanks for taking this on.

Comment on lines +75 to +78
const cdpSession = await this._page.target().createCDPSession();
this._targetManager = new TargetManager(cdpSession);
await this._targetManager.enable();
this.defaultSession = this._targetManager.rootSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big fan of avoiding the double session object! (I was seeing that at the CDP traffic level. so weird.)

const cdpSession = await this._page.target().createCDPSession();
this._targetManager = new TargetManager(cdpSession);
await this._targetManager.enable();
this.defaultSession = this._targetManager.rootSession();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd love to s/defaultSession/rootSession/g but fine with it happening in a followup.


await session.sendCommand('Target.setAutoAttach', {
// We want to receive information about network requests from iframes, so enable the Network domain.
await newSession.sendCommand('Network.enable');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think we should also tweak this to do a promise.all style? 4bc0b05
(im still surprised this is fine without it)
also.. i wonder if the finally case hits because of a protocol_timeout on one of these?

i know you saw some patterns in pptr/playwright which felt more confident around this stuff. dunno if that's relevant.

@connorjclark connorjclark changed the title core: make targetManager accessible on driver core: make target manager accessible on driver Jun 13, 2022
Comment on lines +42 to +46
targetManager: {
rootSession(): FRProtocolSession;
on(event: 'protocolevent', callback: (payload: Protocol.RawEventMessage) => void): void
off(event: 'protocolevent', callback: (payload: Protocol.RawEventMessage) => void): void
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could give this its own interface. Then the target manager and legacy shim will implement that interface.

Might help with some of the event type TS stuff you did in target-manager.js

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hoping that it'll stay nice and simple until LH 11, and then needing an interface won't even be a question with legacy gone, it'll just be itself.

const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');

/** @typedef {import('../driver/target-manager.js')} TargetManager */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used?

it's not, deleted :)

@brendankenny
Copy link
Member Author

brendankenny commented Jun 21, 2022

Addressed feedback and unit tests updated. Test updates are in separate commits to make it slightly easier to review.

Let's add a mock simplification pass to our project TODOs, that was way harder (and more than 2x the lines changed) than refactoring the actual code :)

@@ -31,58 +31,6 @@ describe('ProtocolSession', () => {
session = new ProtocolSession(puppeteerSession);
});

describe('ProtocolSession', () => {
Copy link
Member Author

@brendankenny brendankenny Jun 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests in here moved to target-manager-test.js

@connorjclark
Copy link
Collaborator

connorjclark commented Jun 22, 2022

Should help significantly with #14078. Smoke tests should all pass, but waiting on feedback before touching the unit test mocks :)

This seems to close out the linked issue (I'm inferring from this quoted text that there is more to do, but can't tell what).

@brendankenny
Copy link
Member Author

Should help significantly with #14078. Smoke tests should all pass, but waiting on feedback before touching the unit test mocks :)

This seems to close out the linked issue (I'm inferring from this quoted text that there is more to do, but can't tell what).

I think mostly, but I believe @paulirish has a few more things adjacent to this, like settling on some naming conventions across files, using regular event emitters where possible, etc. We could discuss in #14078 and/or next sync.

@brendankenny brendankenny merged commit a5434c8 into master Jun 22, 2022
@brendankenny brendankenny deleted the tm-on-driver branch June 22, 2022 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants